#include <string>

#include "monad.hpp"
// ================== 辅助函数 ==================
// 需求：在只读环境 `Env`、可变状态 `int` 下写日志 `std::string`
struct Env
{
    double factor;
};

// 定义 MyStack 为一个模板类，而不是类型别名
template <typename A>
using Tmp = ReaderT<Env, StateT<int, A>>;

template <typename A>
class MyStack : public WriterT<std::string, Tmp<A>>
{
public:
    using Base = WriterT<std::string, Tmp<A>>;
    // 构造函数，继承基类
    using Base::Base;

    MyStack() = default;

    // 静态成员函数，用于访问内层 Monad 的功能
    static auto ask()
    {
        // 返回一个 MyStack<Env>，其内部逻辑由 ReaderT::ask() 提供
        return MyStack<Env>{Tmp<Env>::ask()};
    }

    static auto get()
    {
        // 返回一个 MyStack<int>，其内部逻辑由 StateT::get() 提供
        return MyStack<int>{StateT<int, int>::get()};
    }

    static auto tell(std::string w)
    {
        // 返回一个 MyStack<std::monostate>，其内部逻辑由 WriterT::tell() 提供
        return MyStack<std::monostate>{WriterT<std::string, std::monostate, ReaderT<Env, StateT<int, std::monostate>>>::tell(w)};
    }

    static auto put(int s)
    {
        // 返回一个 MyStack<std::monostate>，其内部逻辑由 StateT::put() 提供
        return MyStack<std::monostate>{StateT<int, std::monostate>::put(s)};
    }

    // MyStack 专用的 return 函数
    static auto return_(A value)
    {
        // 将值包装进 MyStack 的上下文中
        return MyStack<A>{mreturn(std::make_tuple(std::move(value), std::string{}))};
    }
};

// 修正后的 computation 定义
auto computation = MyStack<int>::tell("start\n") >>= [](auto)
{
    return MyStack<int>::ask() >>= [](Env e)
    {
        return MyStack<int>::get() >>= [e](int s)
        {
            int n = static_cast<int>(s * e.factor);
            return MyStack<int>::tell("factor applied\n") >> MyStack<int>::put(n) >> MyStack<int>::return_(n);  // 使用 MyStack 专用的 return_
        };
    };
};